ES6 (ECMAScript 2015) - 新特性完整學習指南

📚 練習目標

ES6 (ECMAScript 2015) 是 JavaScript 的一次重大革新。本課程將系統地介紹 ES6 的核心特性,包括新的變量宣告方式、箭頭函數、模板字串、解構賦值、展開運算子、類別、非同步處理等概念。通過這些例子,學生將掌握現代 JavaScript 開發的必要知識。

P1 - let 和 const 變數宣告

為什麼需要 let 和 const?

ES5 只有 var,存在作用域混淆問題。ES6 引入 letconst,提供了更清晰的變量管理方式。

// 區塊作用域(Block Scope) { var a = 1; // 函數作用域,會洩露到全域 let b = 2; // 區塊作用域,只在 {} 內有效 const c = 3; // 區塊作用域,不可重新賦值 } console.log(a); // 1(不好!) console.log(b); // ReferenceError console.log(c); // ReferenceError
知識點:
  • var - 函數作用域,易造成全域污染
  • let - 區塊作用域,可重新賦值
  • const - 區塊作用域,不可重新賦值(最安全)
  • 現代開發推薦優先使用 const,需要更改時用 let

P2 - 箭頭函數 (Arrow Functions)

什麼是箭頭函數?

箭頭函數是一種簡潔的函數語法,同時改變了 this 的綁定方式。箭頭函數會繼承外層的 this,而不是動態綁定。

// ES5 傳統函數 const add = function(a, b) { return a + b; }; // ES6 箭頭函數 const add = (a, b) => { return a + b; }; // 簡寫形式(單一表達式) const add = (a, b) => a + b; // 單一參數可省略括號 const square = x => x * x;
知識點:
  • 箭頭函數使用 => 語法
  • 沒有參數時:() => {}
  • 單一參數時:x => {}
  • 多個參數時:(x, y) => {}
  • 箭頭函數沒有自己的 this,繼承外層的 this
  • 不能用作建構函數(constructor)

P3 - 模板字串 (Template Literals)

模板字串簡化字符串操作

使用反引號(backtick)取代引號,可以直接插入變量和表達式,支援多行字符串。

// ES5 字符串拼接 const name = "Alice"; const age = 25; const msg = "My name is " + name + " and I'm " + age + " years old."; // ES6 模板字串 const msg = `My name is ${name} and I'm ${age} years old.`; // 支援多行 const html = ` <div> <p>${name}</p> <p>Age: ${age}</p> </div> `; // 支援表達式 const result = `The sum is ${10 + 20}`; // 30
知識點:
  • 使用反引號(`)包含字符串
  • ${} 插入變量或表達式
  • 支援多行字符串,無需 + 拼接
  • 可在 ${} 中進行任何 JavaScript 表達式運算

P4 - 解構賦值 (Destructuring Assignment)

快速從陣列或物件中提取值

解構賦值允許我們用更簡潔的方式從陣列或物件中提取值並賦給變量。

// 陣列解構 const [a, b, c] = [1, 2, 3]; console.log(a, b, c); // 1 2 3 // 跳過某些值 const [x, , z] = [10, 20, 30]; console.log(x, z); // 10 30 // 物件解構 const {name, age} = {name: 'Bob', age: 30, city: 'NYC'}; console.log(name, age); // Bob 30 // 物件解構並重新命名 const {name: personName, age: personAge} = {name: 'Charlie', age: 28}; console.log(personName, personAge); // Charlie 28 // 設定預設值 const {name = 'Unknown', city = 'Taipei'} = {name: 'David'}; console.log(name, city); // David Taipei
知識點:
  • 陣列解構:按順序提取值
  • 物件解構:按屬性名稱提取值
  • 可用逗號跳過不需要的值
  • 可設定預設值以防值不存在
  • 可重新命名以避免名稱衝突

P5 - 展開運算子 (...) 與其餘參數 (Rest Parameters)

... 運算子的雙重作用

展開運算子(Spread)用於展開陣列或物件,其餘參數(Rest)用於收集多個參數。雖然語法相同,但用途不同。

// 展開(Spread)- 展開陣列 const arr1 = [1, 2, 3]; const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5] // 展開物件 const obj1 = {a: 1, b: 2}; const obj2 = {...obj1, c: 3}; // {a: 1, b: 2, c: 3} // 其餘參數(Rest)- 收集多個參數 function sum(...numbers) { return numbers.reduce((total, num) => total + num, 0); } console.log(sum(1, 2, 3, 4, 5)); // 15 // 混合用法 function greet(greeting, ...names) { console.log(`${greeting}, ${names.join(' and ')}`); } greet('Hello', 'Alice', 'Bob', 'Charlie'); // Hello, Alice and Bob and Charlie
知識點:
  • 展開:在函數呼叫或陣列/物件字面量中展開元素
  • 其餘參數:在函數參數列表中收集剩餘的參數
  • 展開陣列可用於複製、合併陣列
  • 其餘參數必須是參數列表中的最後一個
  • 可用於函數參數、陣列、物件字面量

P6 - 變數提升 (Hoisting)

理解 JavaScript 的執行過程

Hoisting 是 JavaScript 引擎在執行代碼前的預處理階段。var 和函數聲明會被提升,但 letconst 不會真正提升,而是進入「暫時死亡區」(Temporal Dead Zone)。

// var 的提升 - 聲明被提升,但初始化不提升 console.log(x); // undefined(不是 ReferenceError) var x = 5; console.log(x); // 5 // let / const 的暫時死亡區 console.log(y); // ReferenceError! let y = 10; // 函數聲明會完全被提升 sayHello(); // 正常執行 function sayHello() { console.log("Hello!"); } // 函數表達式不會被提升 sayGoodbye(); // TypeError const sayGoodbye = () => console.log("Goodbye!");
知識點:
  • var 聲明被提升,但初始化值不提升(結果為 undefined)
  • letconst 進入暫時死亡區,不能在宣告前使用
  • 函數聲明完全被提升
  • 函數表達式不被提升(只有變量提升)
  • 這是為什麼避免使用 var 的重要原因

P7 - setTimeout 與非同步執行

JavaScript 的單線程與非同步

setTimeout 是一個非同步函數,它延遲執行代碼。理解 setTimeout 對於理解事件迴圈(Event Loop)和回調地獄(Callback Hell)至關重要。

// 基本用法 setTimeout(() => { console.log("After 1 second"); }, 1000); console.log("Immediately"); // 輸出順序: // Immediately // After 1 second // 清除 timeout const id = setTimeout(() => { console.log("This won't appear"); }, 1000); clearTimeout(id); // 取消這個 timeout // setInterval - 重複執行 const intervalId = setInterval(() => { console.log("Every 1 second"); }, 1000); setTimeout(() => { clearInterval(intervalId); // 1 秒後停止 }, 5000);
知識點:
  • setTimeout 是非同步的,不會阻塞代碼執行
  • setInterval 重複執行,可用 clearInterval 停止
  • 第二個參數是延遲毫秒數
  • 回調函數在延遲時間後加入事件佇列,而非立即執行
  • 理解這個概念對學習 Event Loop 很重要

P8 - 條件式中的 let 與作用域

區塊作用域在條件語句中的應用

使用 letif 和迴圈中宣告變量,會限制其作用域在該區塊內,避免全域污染。

// 在 if 中使用 let if (true) { let x = 10; console.log(x); // 10 } console.log(x); // ReferenceError // 在迴圈中使用 let(重點!) for (let i = 0; i < 3; i++) { // 每次迴圈 i 都是新的區塊作用域 console.log(i); // 0, 1, 2 } console.log(i); // ReferenceError // 與 var 的對比 for (var j = 0; j < 3; j++) { setTimeout(() => { console.log(j); // 3, 3, 3(不是想要的!) }, 100); } for (let k = 0; k < 3; k++) { setTimeout(() => { console.log(k); // 0, 1, 2(正確!) }, 100); }
知識點:
  • let 在區塊内({})宣告時,作用域限制在該區塊
  • 在迴圈中使用 let,每次迭代都會建立新的作用域
  • 這解決了 var 在迴圈中常見的閉包問題
  • 使用 let 可以避免許多難以追蹤的 bug

P9 - 常數 (const) 與最佳實踐

優先使用 const,其次使用 let

const 宣告的變量不能被重新賦值,這使代碼更加可預測和安全。當需要改變值時,才使用 let

// 常數宣告 const PI = 3.14159; const MAX_USERS = 100; const CONFIG = { host: 'localhost', port: 3000 }; // 嘗試重新賦值會報錯 PI = 3.14; // TypeError! // 但物件屬性可以改變(const 保護的是引用,不是內容) CONFIG.port = 3001; // 可以! console.log(CONFIG.port); // 3001 // 物件本身不能重新賦值 CONFIG = {}; // TypeError! // 當需要改變值時,使用 let let counter = 0; counter++; // 正確 console.log(counter); // 1
知識點與最佳實踐:
  • 預設使用 const:不會被重新賦值的變量應該用 const
  • 需要改變時用 let:只有當變量需要重新賦值時才用 let
  • 避免使用 var:在現代代碼中不應該使用 var
  • const 保護的是引用,不是值本身(物件屬性仍可改變)
  • 這個習慣可以減少 bug,因為 const 強制你在宣告時初始化,並防止意外重新賦值

P10 - 其他重要的 ES6 主題

ES6 還有更多特性值得學習

除了上述特性外,ES6 還包括:

  • 類別(Classes) - 更接近傳統 OOP 的語法
  • Promise - 處理非同步操作的優雅方式
  • for...of 迴圈 - 遍歷可迭代對象
  • 模組(Modules) - import/export 實現模組化
  • Map 和 Set - 新的資料結構
  • Symbol - 新的原始資料型別

推薦學習路線

  1. 掌握 letconst - 這是基礎
  2. 習慣箭頭函數和模板字串 - 提高代碼可讀性
  3. 深入理解解構和展開 - 減少樣板代碼
  4. 理解 hoisting 和作用域 - 避免常見 bug
  5. 掌握非同步概念(setTimeout、Promise、async/await)
  6. 學習類別和模組化開發

ES5 vs ES6 比較表

特性 ES5 ES6+ 推薦用法
變量宣告 var x = 1; let x = 1; / const x = 1; 優先 const,需要改變用 let
函數 function add(a, b) { return a + b; } const add = (a, b) => a + b; 箭頭函數更簡潔,但注意 this
字符串 "Hello " + name `Hello ${name}` 模板字串更清晰易讀
提取值 const a = arr[0]; const b = arr[1]; const [a, b] = arr; 解構更簡潔高效
作用域 函數作用域(容易混淆) 區塊作用域(清晰明確) 使用 let/const 避免問題
非同步 嵌套回調 Promise、async/await 避免回調地獄,使用 Promise 或 async/await

📋 ES6 核心概念總結

七個必須掌握的 ES6 概念

  1. let 和 const - 現代變量宣告的基石
  2. 箭頭函數 - 簡潔的函數語法和 this 綁定
  3. 模板字串 - 更優雅的字符串操作
  4. 解構賦值 - 快速提取和賦值
  5. 展開運算子與其餘參數 - 靈活的參數處理
  6. 作用域與 Hoisting - 理解代碼執行順序
  7. 非同步概念 - setTimeout、Promise、async/await
學習建議:
  • 🔗 按順序進行 - 從簡單概念開始,逐步深入
  • 💻 動手實踐 - 在瀏覽器開發者工具中運行示例代碼
  • 🎯 理解概念而非背誦 - 理解為什麼要這樣做,而非只知道怎麼做
  • 📚 參考官方文檔 - MDN 和 ECMAScript 標準是最可靠的資源
  • 🧪 進行小實驗 - 修改示例代碼,看看會發生什麼
成果展示

Final 示範頁

下面集中列出適合公開查看的成果頁與示範頁。